import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { messageMatch } from './status'
import { getToken, TokenPrefix, AccessToken } from '@/utils/auth'
import { ObjectToString, Guid, decodeObj } from '../tools'
import { BASE_PATH } from '@/config/index'
import { message } from 'ant-design-vue'
interface AxiosRequestExpandConfig extends AxiosRequestConfig {
  // Is token not required
  isNoToken?: boolean
  // Whether to use the full path
  rootPath?: boolean
  // Whether to automatically concatenate objects into strings
  automaticQuery?: boolean
  isSNoTip?: boolean
  sTipStr?: string
  data?: any
}

// If the request takes longer than `timeout`, the request will be aborted
axios.defaults.timeout = 10000
// Indicates whether credentials are required for cross-origin requests
axios.defaults.withCredentials = false
// allow cross-domain
axios.defaults.headers.post['Access-Control-Allow-Origin-Type'] = '*'
axios.defaults.headers.common['Accept-Language'] = 'zh-CN'
axios.defaults.headers.common['timeOffset'] = new Date().getTimezoneOffset() * 60 * 1000
// Anti-heavy anti-attack timestamp
axios.defaults.headers.common['timestamp'] = +new Date()
// Anti-heavy anti-attack random number
axios.defaults.headers.common['nonce'] = `web-${Guid()}-${+new Date()}`
axios.defaults.headers.common['version'] = 'v8'

const axiosInstance: AxiosInstance = axios.create({
  baseURL: import.meta.env.BASE_URL + '',
})

// The axios instance intercepts the response
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    if (response.data.data) response.data.data = decodeObj(response.data.data)
    if (response.status === 200) {
      if (!response.data.success) {
        message.error(response.data.errMsg)
        return Promise.reject(response.data)
      }
      return Promise.resolve(response.data || response)
    }
    return Promise.resolve(response.data || response)
  },
  // Request failed
  (error: any) => {
    const { response } = error
    if (response) {
      if (response.status == 401) {
        // Timeout/Unauthorized Case Handling
      }
      // prompt error message
      message.error(messageMatch(response.status))
      return Promise.reject(response.data)
    }
    // prompt error message
    message.error('The network connection is abnormal, please try again later!')
  },
)

// Axios instance intercepts requests
axiosInstance.interceptors.request.use(
  (config: AxiosRequestExpandConfig) => {
    const token = getToken()
    // Interface authentication, token setting
    if (token && !config.isNoToken && config.headers && config.url) {
      config.headers.Authorization = config.url.includes('access_token=')
        ? AccessToken
        : `${TokenPrefix}${token}`
    }
    const path = config.rootPath ? config.url : BASE_PATH + config.url
    config.url = config.automaticQuery ? ObjectToString(path as string, config.data) : path
    return config
  },
  (error: any) => {
    return Promise.reject(error)
  },
)

const request = <T = any>(
  config: AxiosRequestExpandConfig,
  options?: AxiosRequestExpandConfig,
): Promise<T> => {
  if (!options) {
    return new Promise((resolve, reject) => {
      axiosInstance
        .request<T, T>({
          ...config,
        })
        .then((data: any) => {
          message.success('Successful operation')
          resolve(data)
        })
        .catch((e: any) => {
          reject(e)
        })
    })
    // throw new Error('Please configure the correct request parameters');
  } else {
    return new Promise((resolve, reject) => {
      axiosInstance
        .request<T, T>({
          ...config,
          ...options,
        })
        .then((data: any) => {
          const msg = options && options.sTipStr ? options.sTipStr : 'Successful operation'
          !options.isSNoTip && message.success(msg)
          resolve(data)
        })
        .catch((e: any) => {
          reject(e)
        })
    })
  }
}

export function get<T = any>(url: string, options?: AxiosRequestExpandConfig): Promise<T> {
  return request({ url: url, method: 'GET' }, options)
}

export function post<T = any>(url: string, options?: AxiosRequestExpandConfig): Promise<T> {
  return request({ url: url, method: 'POST' }, options)
}

export function put<T = any>(url: string, options?: AxiosRequestExpandConfig): Promise<T> {
  return request({ url: url, method: 'put' }, options)
}

export function del<T = any>(url: string, options?: AxiosRequestExpandConfig): Promise<T> {
  return request({ url: url, method: 'delete' }, options)
}

export default request

export type { AxiosInstance, AxiosResponse }
